﻿using NationalInstruments.DAQmx;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using NationalInstruments.DAQmx;                //引入DAQmx命名空间
using Task = NationalInstruments.DAQmx.Task;    //引入DAQmx任务命名空间
using System.IO;                                //引入文件操作命名空间
using ClosedXML.Excel;                          // 引入ClosedXML命名空间
using DocumentFormat.OpenXml.Spreadsheet;       //引入OpenXML命名空间
using EasyModbus;                               //引入EasyModbus命名空间

namespace project
{
    public partial class Form1 : Form
    {
        string TxT_name;
        string TxT_Project = ".txt";

        string Excal_Path;
        string TxT_Path ;

        public Form1()
        {
            InitializeComponent();
            Once_show(); // 显示一次设备名称

        }
        public void Once_show()
        {
            Excal_textBox.Text = @"C:\Users\admin\Desktop\test"; // 设置Excel文件路径
         
            NI_device_name.Text = "Dev1"; // 设置设备名称
            NI_device_channel1.Text = "ai"; // 设置设备名称
            NI_device_channel2.Text = "ai"; // 设置设备名称
            NI_device_channel3.Text = "ai"; // 设置设备名称
            NI_device_channel4.Text = "ai"; // 设置设备名称
            NI_device_channel5.Text = "ai"; // 设置设备名称
            NI_device_channel6.Text = "ai"; // 设置设备名称
            NI_device_channel7.Text = "ai"; // 设置设备名称
            NI_device_channel8.Text = "ai"; // 设置设备名称
            NI_device_channel9.Text = "ai"; // 设置设备名称

            
        }

        //创建类对象
        NI ni = new NI();           // 创建NI对象
        TxT txt = new TxT();        // 创建TxT对象
        Excel excel = new Excel();  // 创建Excel对象
        PLC plc = new PLC();        // 创建PLC对象

        int count;                  // Excel表格行数
        int count_Now;              //正在执行的行数
        int Sin_Flag;               //正弦运动标志位
        string NI_name;
        int NI_count;
        string[] NI_device_channel;

        //Excal数据与PLC参数整理
        public void Data_Reduction()
        {
            Excal_Path = Excal_textBox.Text+ ".xlsx";
            count = excel.Excal_Range(Excal_Path);      // 获取Excel表格的行数
            textBox1.Text =count.ToString();

            textBox2.Text =count_Now.ToString();
            //文件路径与名称属性赋值
            TxT_name = count_Now.ToString();
            TxT_Path = Excal_textBox.Text + TxT_name + TxT_Project;
            TxT_textBox.Text = TxT_Path; // 设置文本框显示文件名

            NI_name = NI_device_name.Text;
            NI_count = int.Parse(NI_device_count.Text); // 设置通道数量
            NI_device_channel = new string[]{
                            "/"+NI_device_channel1.Text,
                            "/"+NI_device_channel2.Text,
                            "/"+NI_device_channel3.Text,
                            "/"+NI_device_channel4.Text,
                            "/"+NI_device_channel5.Text,
                            "/"+NI_device_channel6.Text,
                            "/"+NI_device_channel7.Text,
                            "/"+NI_device_channel8.Text,
                            "/"+NI_device_channel9.Text};



            //参数写入
            float X_location = excel.Excel_Read(Excal_Path, count_Now, 1);
            float Y_location = excel.Excel_Read(Excal_Path, count_Now, 2);
            float Z_location = excel.Excel_Read(Excal_Path, count_Now, 3);

            float X_speed = excel.Excel_Read(Excal_Path, count_Now, 4);
            float Y_speed = excel.Excel_Read(Excal_Path, count_Now, 5);
            float Z_speed = excel.Excel_Read(Excal_Path, count_Now, 6);
            float R_speed = excel.Excel_Read(Excal_Path, count_Now, 7);

            float ax = excel.Excel_Read(Excal_Path, count_Now, 8);
            float fx = excel.Excel_Read(Excal_Path, count_Now, 9);
            float ox = excel.Excel_Read(Excal_Path, count_Now, 10);
            float ay = excel.Excel_Read(Excal_Path, count_Now, 11);
            float fy = excel.Excel_Read(Excal_Path, count_Now, 12);
            float oy = excel.Excel_Read(Excal_Path, count_Now, 13);
            float az = excel.Excel_Read(Excal_Path, count_Now, 14);
            float fz = excel.Excel_Read(Excal_Path, count_Now, 15);
            float oz = excel.Excel_Read(Excal_Path, count_Now, 16);
            float ar = excel.Excel_Read(Excal_Path, count_Now, 17);
            float fr = excel.Excel_Read(Excal_Path, count_Now, 18);
            float or = excel.Excel_Read(Excal_Path, count_Now, 19);

            string str= ax.ToString()+ "\t" +
                        fx.ToString()+ "\t" +
                        ox.ToString()+ "\t" +
                        ay.ToString()+ "\t" +
                        fy.ToString()+ "\t" +
                        oy.ToString()+ "\t" +
                        az.ToString()+ "\t" +
                        fz.ToString()+ "\t  " +
                        oz.ToString()+ "\t" +
                        ar.ToString()+ "\t" +
                        fr.ToString()+ "\t" +
                        or.ToString();

            textBox3.Text = str;
            File.AppendAllText(TxT_Path, "ax\tfx\tox\tay\tfy\toy\taz\tfz\toz\tar\tfr\tor");
            File.AppendAllText(TxT_Path, Environment.NewLine);
            File.AppendAllText(TxT_Path, str);
            File.AppendAllText(TxT_Path, Environment.NewLine);
            Sin_Flag = (int)excel.Excel_Read(Excal_Path, count_Now, 21); //读取正弦运动标志位

            excel.Excel_Write(Excal_Path, count_Now, TxT_Path); // 将文本文件路径写入Excel表格中
            count_Now++; // 更新当前行数

            plc.PLC_RunHopeLocation(X_location, Y_location, Z_location);
            plc.PLC_RunSpeed(X_speed, Y_speed, Z_speed, R_speed);
            plc.PLC_Sin_Var(ax, fx, ox, ay, fy, oy, az, fz, oz, ar, fr, or);


        }

        private void Data_button_Click(object sender, EventArgs e)
        {
             plc.PLC_Connect("192.168.1.100");                              // 连接PLC
             count_Now = 2;
             Data_Reduction();                                              //初始化参数写入
             plc.PLC_Run();
        }

        private void Collection_button_Click(object sender, EventArgs e)
        {

            //采集时间与间隔属性赋值         
            timer_ms.Interval = 1000;   // 设置采集定时器间隔为1秒
            timer_Clock.Interval = int.Parse(Collection_Timer_textBox .Text)* 1000; // 在界面中读取设置时钟定时器间隔秒

            //启动时采集按键绿色
            Collection_button.BackColor = System.Drawing.Color.Green; // 设置按钮颜色为绿色

            timer_ms.Enabled = true;    // 启动采集定时器

        }

        private void timer_ms_Tick(object sender, EventArgs e)  //数据采集频率
        {
            timer_Clock.Enabled = true;                         // 启动时钟定时器

            // 定义数据数组
            double[] NI_Collect_Data;
            NI_Collect_Data = ni.ReadAIOnce(NI_name, NI_count, NI_device_channel);

            // 数据记录在TXT文件中
            TxT.InitializeLogFile(TxT_Path, NI_Collect_Data);
            /*PLC正弦运动指令*/
            if (Sin_Flag == 0) //判断是否正弦运动
            {
                plc.PLC_Sin_Run(true, false, false, false); // PLC正弦运动指令
            }
            else if (Sin_Flag == 1) //判断是否正弦运动
            {
                plc.PLC_Sin_Run(false, true, false, false); // PLC正弦运动指令
            }
            else if (Sin_Flag == 2) //判断是否正弦运动
            {
                plc.PLC_Sin_Run(false, false, true, true); // PLC正弦运动指令
            }
            else
            {
                plc.PLC_Sin_Run(false, false, false, true); // PLC正弦运动指令
            }
        }

        private void timer_Clock_Tick(object sender, EventArgs e) //数据采集定时器
        {
            /*PLC正弦停止程序*/
            plc.PLC_Sin_Stop();       // PLC正弦停止指令
            timer_ms.Enabled = false; // 停止采集定时器           
         
            timer_Clock.Enabled = false; // 停止时钟定时器

            time.Enabled = true;        // 启动数据整理定时器

        }

        private void time_Tick(object sender, EventArgs e)      //数据整理时间
        {
           if(count_Now == count+1) //判断是否到达最后一行
            {
                timer_Clock.Enabled = false;        // 停止时钟定时器
                time.Enabled = false;               // 停止数据整理定时器
                Collection_button.BackColor = System.Drawing.Color.Red; //采集停止时采集按键红色
                return ;
            }

            //数据整理
            Data_Reduction();

            /*PlC位置运动程序*/
            plc.PLC_Run(); // PLC运动指令
            time.Enabled = false;       // 停止数据整理定时器
            PLC_Run_timer.Enabled = true;
        }

        private void PLC_Run_timer_Tick(object sender, EventArgs e)
        {
            timer_ms.Enabled = true;    // 启动采集定时器
            PLC_Run_timer.Enabled = false;
        }

        public class NI
        {
            public double[] ReadAIOnce(string NI_device_name,int NI_device_count, string[] NI_device_channel)
            {
                            
                // 定义数据数组
                double[] NI_Collect_Data;

                // 定义任务名称和通道名称
                string taskName = "analogInputTask";

                // 创建新的DAQmx任务
                Task analogInputTask = new Task(taskName);

                // 添加模拟输入通道
                for(int i=1; i<=NI_device_count; i++)
                {
                    analogInputTask.AIChannels.CreateVoltageChannel(NI_device_name + NI_device_channel[i - 1], "aiChannel" + i, AITerminalConfiguration.Differential, -10.0, 10.0, AIVoltageUnits.Volts);
                }
                //analogInputTask.AIChannels.CreateVoltageChannel("Dev1/ai0", "aiChannel0", AITerminalConfiguration.Differential, -10.0, 10.0, AIVoltageUnits.Volts);
                //analogInputTask.AIChannels.CreateVoltageChannel("Dev1/ai1", "aiChannel1", AITerminalConfiguration.Differential, -10.0, 10.0, AIVoltageUnits.Volts);
                //analogInputTask.AIChannels.CreateVoltageChannel("Dev1/ai2", "aiChannel2", AITerminalConfiguration.Differential, -10.0, 10.0, AIVoltageUnits.Volts);
                //analogInputTask.AIChannels.CreateVoltageChannel("Dev1/ai3", "aiChannel3", AITerminalConfiguration.Differential, -10.0, 10.0, AIVoltageUnits.Volts);
                //analogInputTask.AIChannels.CreateVoltageChannel("Dev1/ai4", "aiChannel4", AITerminalConfiguration.Differential, -10.0, 10.0, AIVoltageUnits.Volts);
                //analogInputTask.AIChannels.CreateVoltageChannel("Dev1/ai5", "aiChannel5", AITerminalConfiguration.Differential, -10.0, 10.0, AIVoltageUnits.Volts);

                // 创建读取器
                AnalogMultiChannelReader reader = new AnalogMultiChannelReader(analogInputTask.Stream);

                // 开始任务
                analogInputTask.Start();

                // 读取数据
                NI_Collect_Data = reader.ReadSingleSample();

                // 停止任务
                analogInputTask.Stop();

                //释放资源
                analogInputTask.Dispose();
                return NI_Collect_Data;
            }
        }

        public class TxT
        {
            public static void InitializeLogFile( string logFilePath, params double[] data)
            {
                for (int i = 0; i < data.Length; i++)
                {
                    File.AppendAllText(logFilePath , $"{data[i]:F4}\t\t");
                }
                File.AppendAllText(logFilePath, Environment.NewLine);
            }
        }
       
        public class Excel
        {
            public int Excal_Range(string Excal_Path)
            {
                //创建或获取操作对象
                XLWorkbook wb = new XLWorkbook(Excal_Path);

                //选择操作的表格
                IXLWorksheet sheet = wb.Worksheet(1);

                //获取被使用的最后一行的行号
                int data = sheet.LastRowUsed().RowNumber();

                return data;
            }

            public float Excel_Read(string Excal_Path, int Coll,int Row)
            {
                float Excal_Data;

                //创建或获取操作对象
                XLWorkbook wb = new XLWorkbook(Excal_Path);

                //选择操作的表格
                IXLWorksheet sheet = wb.Worksheet(1);

                //单元格值读取
                IXLCell cell = sheet.Cell(Coll,Row);

                ////单元格值转换
                Excal_Data = cell.GetValue<float>();
                Excal_Data=(float)Math.Round(Excal_Data,3);


                //文件保存
                wb.Save();

                return Excal_Data;
            }

            public void Excel_Write(string Excal_Path,int Coll, string TxT_Path)
            {

                //创建或获取操作对象
                XLWorkbook wb = new XLWorkbook(Excal_Path);

                //选择操作的表格
                IXLWorksheet sheet = wb.Worksheet(1);

                //创建文本超链接
                sheet.Cell(Coll, 20).Value = "查看文本";
                sheet.Cell(Coll, 20).SetHyperlink(new XLHyperlink(TxT_Path));

                //文件保存
                wb.Save();
            }
       
        }

        public class PLC
        {
            private ModbusClient TCP;

            #region 参数

            int X_Run_M1005 = 1005;
            int Y_Run_M1105 = 1105;
            int Z_Run_M1205 = 1205;

            int X_Sin_Run_M1007 = 1007;
            int Y_Sin_Run_M1107 = 1107;
            int Z_Sin_Run_M1207 = 1207;
            int R_Sin_Run_M1307 = 1307;

            int X_Sin_Stop_M1008 = 1008;
            int Y_Sin_Stop_M1108 = 1108;
            int Z_Sin_Stop_M1208 = 1208;
            int R_Sin_Stop_M1308 = 1308;

            int X_Hope_Location_HD104 = 41192;
            int Y_Hope_Location_HD204 = 41292;
            int Z_Hope_Location_HD304 = 41392;

            int X_Run_Speed_HD102 = 41190;
            int Y_Run_Speed_HD202 = 41290;
            int Z_Run_Speed_HD302 = 41390;
            int R_Run_Speed_HD402 = 41490;

            int Ax_HD110 = 41198;
            int Fx_HD112 = 41200;
            int Ox_HD114 = 41202;
            int Ay_HD210 = 41298;
            int Fy_HD212 = 41300;
            int Oy_HD214 = 41302;
            int Az_HD310 = 41398;
            int Fz_HD312 = 41400;
            int Oz_HD314 = 41402;
            int Ar_HD410 = 41498;
            int Fr_HD412 = 41500;
            int Or_HD414 = 41502;

            #endregion

            /// <summary>
            /// Real型转变成对应的int型
            /// </summary>
            public int[] FloatToInts(float num)
            {
                int[] nums = new int[2];
                byte[] bytes = BitConverter.GetBytes(num);
                nums[0] = BitConverter.ToInt16(bytes, 0); // 低位部分
                nums[1] = BitConverter.ToInt16(bytes, 2);
                return nums;
            }

            /// <summary>
            /// 信捷PLC对应的Real写寄存器
            /// </summary>
            void TCP_Write_Real(int Address, float Data)
            {
                TCP.WriteMultipleRegisters(Address, FloatToInts(Data));
            }

            /// <summary>
            /// 信捷PLC对应的Dint写寄存器
            /// </summary>
            void TCP_Write_Dint(int Address, int Data)
            {
                int Real_Write_holdingRegisters;

                if (Data > 60000 | Data < 0)
                {
                    MessageBox.Show("数据有误！");
                    return;
                }
                if (Data >= 32768)
                {
                    Real_Write_holdingRegisters = -2 * 32768 + Data;
                    TCP.WriteSingleRegister(Address, Real_Write_holdingRegisters);
                }
                else
                {
                    TCP.WriteSingleRegister(Address, Data);

                }
            }

            /// <summary>
            /// 连接PLC，该方法已经在程序中指定了PLC的IP地址和端口号，如有需要请在定义时更改
            /// </summary>
            /// <returns>连接成功返回true，连接失败返回false</returns>
            public bool PLC_Connect(string TCP_IP)
            {
                TCP = new ModbusClient(TCP_IP, 502);
                TCP.Connect();              //连接PLC
                return TCP.Connected;       //返回连接状态
            }

            /// <summary>
            /// 断开PLC连接
            /// </summary>
            /// <returns>无返回值</returns>
            public void PLC_Disconnect()
            {
                TCP.Disconnect();
            }

            /// <summary>
            /// 控制PLC运动到指定位置
            /// </summary>
            public void PLC_RunHopeLocation(double X_HopeLocation, double Y_HopeLocation, double Z_HopeLocation)
            {

                int X = (int)(X_HopeLocation * 100);
                int Y = (int)(Y_HopeLocation * 100);
                int Z = (int)(Z_HopeLocation * 100);

                TCP_Write_Dint(X_Hope_Location_HD104, X);
                TCP_Write_Dint(Y_Hope_Location_HD204, Y);
                TCP_Write_Dint(Z_Hope_Location_HD304, Z);

            }

            public void PLC_Run()
            {
                TCP.WriteSingleCoil(X_Run_M1005, true);
                TCP.WriteSingleCoil(Y_Run_M1105, true);
                TCP.WriteSingleCoil(Z_Run_M1205, true);
            }

            /// <summary>
            /// 控制PLC运动的速度
            /// </summary>
            public void PLC_RunSpeed(double X_Speed, double Y_Speed, double Z_Speed, double R_Speed)
            {
                int X = (int)(X_Speed * 100);
                int Y = (int)(Y_Speed * 100);
                int Z = (int)(Z_Speed * 100);
                int R = (int)(R_Speed * 100);

                TCP_Write_Dint(X_Run_Speed_HD102, X);
                TCP_Write_Dint(Y_Run_Speed_HD202, Y);
                TCP_Write_Dint(Z_Run_Speed_HD302, Z);
                TCP_Write_Dint(R_Run_Speed_HD402, R);

            }

            /// <summary>
            /// 控制PLC正弦运动的参数
            /// </summary>
            public void PLC_Sin_Var(float ax, float fx, float ox, float ay, float fy, float oy, float az, float fz, float oz, float ar, float fr, float or)
            {
                //int Ax = (int)(ax * 100);               
                //int Ox = (int)(ox * 100);

                //int Ay = (int)(ay * 100);
                //int Oy = (int)(oy * 100);

                //int Az = (int)(az * 100);
                //int Oz = (int)(oz * 100);

                //int Ar = (int)(ar * 100);
                //int Or = (int)(or * 100);

                int Ax =(int)Math.Round(ax * 100);
                int Ox =(int)Math.Round(ox * 100);
                int Ay =(int)Math.Round(ay * 100);
                int Oy =(int)Math.Round(oy * 100);
                int Az =(int)Math.Round(az * 100);
                int Oz =(int)Math.Round(oz * 100);
                int Ar =(int)Math.Round(ar * 100);
                int Or =(int)Math.Round(or * 100);

                //X
                TCP_Write_Dint(Ax_HD110, Ax);
                TCP_Write_Real(Fx_HD112, fx);
                TCP_Write_Dint(Ox_HD114, Ox);

                //Y
                TCP_Write_Dint(Ay_HD210, Ay);
                TCP_Write_Real(Fy_HD212, fy);
                TCP_Write_Dint(Oy_HD214, Oy);

                //Z
                TCP_Write_Dint(Az_HD310, Az);
                TCP_Write_Real(Fz_HD312, fz);
                TCP_Write_Dint(Oz_HD314, Oz);

                //R
                TCP_Write_Dint(Ar_HD410, Ar);
                TCP_Write_Real(Fr_HD412, fr);
                TCP_Write_Dint(Or_HD414, Or);

            }

            /// <summary>
            /// 控制PLC正弦运动开始
            /// </summary>
            /// 
            public void PLC_Sin_Run(bool x, bool y, bool z, bool r)
            {
                if (x) { TCP.WriteSingleCoil(X_Sin_Run_M1007, true); }
                if (y) { TCP.WriteSingleCoil(Y_Sin_Run_M1107, true); }
                if (z) { TCP.WriteSingleCoil(Z_Sin_Run_M1207, true); }
                if (r) { TCP.WriteSingleCoil(R_Sin_Run_M1307, true); }
            }

            /// <summary>
            /// 控制PLC正弦运动停止
            /// </summary>
            /// 
            public void PLC_Sin_Stop()
            {
                TCP.WriteSingleCoil(X_Sin_Stop_M1008, false);
                TCP.WriteSingleCoil(Y_Sin_Stop_M1108, false);
                TCP.WriteSingleCoil(Z_Sin_Stop_M1208, false);
                TCP.WriteSingleCoil(R_Sin_Stop_M1308, false);
            }

        }

        private void Excal_textBox_TextChanged(object sender, EventArgs e)
        {

        }
    }
}
